CUBE CONNECT Edition Help

Using the Highway Program

This section provides helpful information about using CUBE Voyager’s Highway program. Topics include:

Highway introduction

The Highway program now supports junction or intersection constrained assignment as well as the typically link based capacity constrained assignment. Junction-constrained assignment requires the coding of the junction or intersection movements and controls. The descriptions below refer to link based traffic assignment. Refer to Intersection modeling for a detailed description of intersection modeling and the data requirements.

The Highway program now can write the full path file from an assignment run including full results from every iteration. This makes many forms of path based analysis directly accessible in CUBE without having to rerun the assignments with specific commands in the scripts. See the description of PATHO in FILEO and PATHLOAD; also refer to Highway path display for information about path-based analysis in CUBE.

The Highway program’s primary function is to assign trips to highway network links. A highway network, zonal matrices, zonal data, junction data and turn penalties can be input, and a loaded network, new matrices, turning volumes, final junction delay and reports can be output. There are basic default operations, but the user can control much of the process.

A typical assignment program builds paths based upon link costs (impedance) and assigns trips to those paths for each origin zone. After all origin zones have been processed, link costs are updated based upon the level of congestion on each link. Then the entire path and assignment process is repeated. This process continues until some criteria for termination is reached. The volumes from each iteration are combined to form a weighted assignment. Different criteria are used to determine when enough iterations have been performed. Almost all of the operations follow a fixed pattern, and are driven by basic parameters. Various options are usually available to provide the user with additional outputs. Select link analysis is a major tool for most users. This process "traps" the trips that meet the select link criteria, and usually writes them to output matrices.

The Highway program provides the same capabilities as a traditional assignment program, but functions somewhat differently. There are only a few automatic operations, and global parameters are used sparingly. The program operates by processing in various phases. In each phase the program performs certain specific operations, and optionally processes a stack of operations provided by the user for that phase.

In addition to phase operations, the user can enter FUNCTION statements (in the form of numerical expressions) that are to be performed in place of default functions at certain times by the program.

  • Using the FUNCTION control statement, the user may calculate the cost, congested time, or volume (at the current iteration) of a link. See FUNCTION.

  • FUNCTION is also ideal for modeling multiple user class assignments (such as regular vs. HOV traffic). For more information and an example, see Multiple user class assignment using generalized cost functions.

For normal processing, there must be a way of computing certain required values for each link. If there is no automatic way for the program to determine these values, the user must supply the process to obtain them. Normally, the values are computed directly from the variables in the input network, but since there is no fixed format of the network, the required variables may not be present. In that case, the LINKREAD phase can be used and formulated to provide these values. The underlying assumption is that path building and capacity restraint are based upon a generalized cost on each link. In most cases, the cost is time. There are several ways to obtain the free flow time (T0), and the initial path time (T1). The hierarchy of the processes to obtain T0 and T1 is outlined below, in the description of the LINKREAD phase.

The best advice is that the network should contain a variable that can be used directly for T0, or that it contains variables so that DISTANCE and SPEED information can be easily obtained. If the variables DISTANCE, LANES, and SPDCLASS are in the network, T0 can be computed from the DISTANCE and the values from the SPDTAB speed table.

If the network is the result of conversion from a TRANPLAN network, it will usually contain variables named DISTANCE, TIME1, and CAPACITY. DISTANCE and TIME1 are usually in hundredths of miles and hundredths of minutes, respectively. CAPACITY is normally the total capacity for the link. TIME1 is the starting time for assignment, and is not necessarily a true T0 (free flow time). If such a network is used directly, the LINKREAD stack should contain the following statements:

DISTANCE=LI.DISTANCE/100 ; not absolutely necessary
T0 = LI.TIME1/100
C = LI.CAPACITY * CAPFAC ; factor to get on same scale with trips

In reality, it would be better to rename and scale the variables appropriately during the network conversion process, so that it is not necessary to remember to deal with them in the Highway program.

TRANPLAN converted networks will be in nearly the correct format, but the user should also be aware to scale the variables to the correct values. If the network distance is properly scaled, T0 will be computed from the DISTANCE, SPDCLASS, LANES, and the SPEED portion of the SPDCAP tables.

The major phases in the process are:

  • SETUP - Optionally, initialize basic user arrays and processes

  • LINKREAD - Obtain required values for each link

  • ILOOP - Build paths and assign trips from each origin zone

  • ADJUST - Examine iteration results, test for convergence and adjust link values for next iteration

  • CONVERGE - Optional phase where user can specify their own convergence rules and stopping criteria

These phases are processed even if the user does not explicitly specify any controls for them. However, if there is no explicit ILOOP phase, the program will terminate with an appropriate message. The phases are specified by using PROCESS PHASE=PhaseName statements; for simplistic purposes, most users simply use the short form: PHASE=PhaseName without the PROCESS control word. A PHASE is closed with either an ENDPROCESS or an ENDPHASE statement. These two statements are interchangeable. A PHASE will also be closed if an new PROCESS PHASE=PhaseName or PHASE=PhaseName statement is encountered prior to an ENDPROCESS or ENDPHASE.

For more information about phases, see Phases.

Highway program control statement overview

There are several types of control statements in the Highway program:

Definition statements - Define static processes. Examples include:

Computational statements - Update variable values. Examples include:

Reporting statements - Accumulate or dynamically display values. Examples include:

Flow control statements - Set statement order. Examples include:

For details about control statements, see Control Statements.

Functions and built-ins

This section lists built-in variables, arrays, and functions that can assist in performing most desired operations:

Note: The names are not case sensitive, but capitalization may make them a bit more meaningful.

You can also use FUNCTION statements to enter single expressions for computing certain values. See FUNCTION.

Built-in variables

Only the variables with a * may be stored into by the user; the others are reserved.

  • _SKIPTOI - In the ILOOP phase, jump to the specified zone immediately. Its value is checked at the end of the current I. If specified, CUBE Voyager sets I to that value. The specified value must be greater than the current I. See Example of _SKIPTOI

  • C* - Capacity used in congestion expressions;

  • DISTANCE* - Link distance expressed in miles or kilometers.

  • FIRSTZONE - Stores the zone number of the first zone being processed. In a normal run this is 1. Under intrastep distributed processing with CUBE Cluster, this is the first zone number of the zones to be processed on the current CUBE Cluster node.

  • I - Current row’s zone (ILOOP).

  • ITERATION - Current iteration number.

  • J - Column index, usually 1, and varies (1-Zones) for MW[] and JLOOPs.

  • LAMBDA - Lambda value computed for this iteration; do not be reset.

  • LASTITERATION - Last iteration indicator, usually set to the MAXITERS parameter.

  • LASTZONE - Stores the last zone number to be processed. In a normal run this would be the same as ZONES. Under intrastep distributed processing with CUBE Cluster, this is the highest zone number to be processed on the current CUBE Cluster node.

  • LINKCLASS* - Class of the current link; you can modify in LINKREAD.

  • LINKNO - Link number (available during any implied link loops).

  • LOWCNT - Result of LOWEST().

  • NODES - Number of nodes.

  • SPEED* - Link speed.

  • T0* - Link free flow time.

  • T1* - Initial iteration time.

  • V* - Total link volume used in ADJUST phase; by default, it is the sum of all VOL[] sets.

  • ZONES - Number of zones.

Built-in arrays

There are arrays that can be referenced with […] to indicate a specific value from the array. Most times, the link-oriented arrays need not be referenced with an index; the default [linkno] is supplied by the program. The names with a * can be stored into, the others are reserved.

  • A - A-nodes for each link.

  • B - B-nodes for each link.

  • COST - Link cost values.

  • DIST* - Link distances.

  • LI.name - Link values from the network.

  • LW.name* - User generated values for links (currently accepts numeric values only).

  • MW[]* A work matrix; see COMP for more details.

  • TIME* - Link times.

  • VOL[]* - Link volumes.

Built-in functions

These built-in functions are described in COMP.

  • ROWSUM(mw) - Row total.

  • ROWCNT(mw) - Number of cells whose values != 0.

  • ROWMIN(mw) - Minimum value in the row.

  • ROWMAX(mw) - Maximum value in the row.

  • ROWAVE(mw) - Average cell value where value!=0.

  • ROWFIX(mw) - Convert mw to integer values (start at column intrazonal + 1).

  • ROWFAC(mw,*fac*) - Factors the row by fac.

  • ROWADD(d,s1,…,sn) - Add matrices MW[s1], MW[s2], … MW[sn] to matrix MW[d].

  • ROWMPY(d,s) - Multiply mw[d] by mw[s].

  • ROWDIV(d,s) - Divide mw[d] by mw[s].

  • LOWEST(mw,#) - Sum of lowest valued cells in a matrix row.

  • LOWCNT - Actual number of cells found by LOWEST function.

  • SPEEDFOR(lanes,class) - Speed from spdtab.

  • CAPACITYFOR(lanes,class) - Capacity from captab.

  • PATHTRACE(value) - Sum of link values (Time, Cost, LI. or LW.) on path for I to J.

  • LINKNUM(a,b) - Link number for link a-b.

  • CHECKNAME(Name) - Check if a matrix table/ zonal file field/ link attribute exists. If it does not exist, the function returns a zero. If it exists, the return code is a 2 digit number in the format of {t}{s}, defined as follows:

    {t} is type

    • 0=single variable

    • 1=vector

    • 2=user function

    • 3=work matrices

    • 4=user function

    • 5=user function

    • 6=vector with constant index and no default index

    • 7=multi-dimension array, no default index

    {s} is storage size

    • 1=numeric size

    • 2=string

    e.g. 1=numeric variable, 2=string variable, 11=numeric array, 12=string array

  • GETVALUE(Name {, DefaultValue}) - Get a numeric value from a matrix table/ zonal file field/ link attribute. This function is used along with the CheckName function. CheckName checks the existence of a matrix table/ zonal file field/ link attribute and GetValue extracts the value from it. They are used to avoid model run crash due to non- existence or invalid value of a matrix table/ zonal file field/ link attribute in the input files.

    • MI.x.x must be used with an explicit JLOOP block where the default index of I and J will be set to the correct origin and destination.

    • ZI.x.x must be used inside the ILOOP Phase so that the default index I will be set to the correct origin zone.

    • LI.x and LW.x must be used inside the LINKREAD Phase, ADJUST Phase or within a LinkLoop block where the default index LinkNo will be set to the correct link.

    PROCESS PHASE=ILOOP
       JLOOP
          IF CheckName(‘MI.1.HBW’)
          hbw =
          GetValue(‘MI.1.HBW’)
    ENDJLOOP
       IF (CheckName(‘ZI.1.SFDUS’) >0)
          SF = GetValue(‘ZI.1.SFDUS’)
    ENDPROCESS
    
    PROCESS PHASE=LINKREAD
       IF(CheckName(‘LI.Capacity’) >0)
          C = GetValue(‘LI.Capacity’)
    ENDPROCESS

GETMATRIXROW(Name,M W# {, DefaultValue})DefaultValue}) - Load a MI matrix row into a MW. This function must be used inside the ILOOP Phase and name must be a MI.x.x name. The return code can be the following:

0=matrix row loaded successfully

1=invalid name or other errors, the default value is used

2=invalid name or other errors and no default value is supplied, program terminating

PROCESS PHASE=ILOOP
   nn=GetMatrixRow(‘MI.1.NHB’, 2,1)
ENDPROCESS

Built-in variables available in the CONVERGE phase

There are various variables available for testing in the CONVERGE phase. See CONVERGE phase for examples of usage.

  • GAP - The GAP for the current iteration. Must be indexed GAP[] for previous iterations.

  • RGAP - The RELATIVEGAP for the current iteration. Must be indexed for previous iterations.

  • AAD - The AAD for the current iteration. Must be indexed for previous iterations.

  • RAAD - The RAAD for the current iteration. Must be indexed for previous iterations.

  • PDIFF - The PDIFF for the current iteration. Must be indexed for previous iterations.

  • RMSE - The RMSE for the current iteration. Must be indexed for previous iterations.

  • BALANCE - Initialized to 0 and set to 1 when convergence criteria have been met.

  • GAPCUTOFF* - Initialized to the value PARAMETERS GAP; may be reset anytime.

  • RGAPCUTOFF* - Initialized to the value PARAMETERS RELATIVEGAP; may be reset anytime.

  • AADCUTOFF* - Initialized to the value PARAMETERS AAD; may be reset anytime.

  • RAADCUTOFF* - Initialized to the value PARAMETERS RAAD; may be reset anytime.

  • PDIFFCUTOFF* - Initialized to the value PARAMETERS PDIFF; may be reset anytime.

  • RMSECUTOFF* - Initialized to the value PARAMETERS RMSE; may be reset anytime.

Built-in functions available in the CONVERGE phase

There are various functions available that return a value for testing in the CONVERGE Phase. See CONVERGE phase for examples of usage.

  • GAPCHANGE - Change in GAP between the specified iteration (the required argument) and the previous iteration.

  • RGAPCHANGE - Change in RELATIVEGAP between the specified iteration (the required argument) and the previous iteration.

  • AADCHANGE - Change in AAD between the specified iteration (the required argument) and the previous iteration.

  • RAADCHANGE - Change in RAAD between the specified iteration (the required argument) and the previous iteration.

  • PDIFFCHANGE - Change in PDIFF between the specified iteration (the required argument) and the previous iteration.

  • RMSECHANGE - Change in RMSE between the specified iteration (the required argument) and the previous iteration.

  • GAPMIN - Minimum GAP between the last n iterations, where n = the number of iterations to process.

  • GAPMAX - Maximum GAP between the last n iterations, where n = the number of iterations to process.

  • GAPAVE - Function that results in the average GAP between the last n iterations, where n = the number of iterations to process.

  • GAPCHANGEMIN - Minimum change in GAP between the last n iterations, where n = the number of iterations to process.

  • GAPCHANGEMAX - Maximum change in GAP between the last n iterations, where n = the number of iterations to process.

  • GAPCHANGEAVE - Average change in GAP between the last n iterations, where n = the number of iterations to process.

  • RGAPMIN - Minimum RELATIVEGAP between the last n iterations, where n = the number of iterations to process.

  • RGAPMAX - Maximum RELATIVEGAP between the last n iterations, where n = the number of iterations to process.

  • RGAPAVE - Average RELATIVEGAP between the last n iterations, where n = the number of iterations to process.

  • RGAPCHANGEMIN - Minimum change in RELATIVEGAP between the last n iterations, where n = the number of iterations to process.

  • RGAPCHANGEMAX - Maximum change in RELATIVEGAP between the last n iterations, where n = the number of iterations to process.

  • RGAPCHANGEAVE - Average change in RELATIVEGAP between the last n iterations, where n = the number of iterations to process.

  • AADMIN - Minimum AAD between the last n iterations, where n = the number of iterations to process.

  • AADMAX - Maximum AAD between the last n iterations, where n = the number of iterations to process.

  • AADAVE - Average AAD between the last n iterations, where n = the number of iterations to process.

  • AADCHANGEMIN - Minimum change in AAD between the last n iterations, where n = the number of iterations to process.

  • AADCHANGEMAX - Maximum change in AAD between the last n iterations, where n = the number of iterations to process.

  • AADCHANGEAVE - Average change in AAD between the last n iterations, where n = the number of iterations to process.

  • RAADMIN - Minimum RAAD between the last n iterations, where n = the number of iterations to process.

  • RAADMAX - Maximum RAAD between the last n iterations, where n = the number of iterations to process.

  • RAADAVE - Average RAAD between the last n iterations, where n = the number of iterations to process.

  • RAADCHANGEMIN - Minimum change in RAAD between the last n iterations, where n = the number of iterations to process.

  • RAADCHANGEMAX - Maximum change in RAAD between the last n iterations, where n = the number of iterations to process.

  • RAADCHANGEAVE - Average change in RAAD between the last n iterations, where n = the number of iterations to process.

  • PDIFFMIN - Minimum PDIFF between the last n iterations, where n = the number of iterations to process.

  • PDIFFMAX - Maximum PDIFF between the last n iterations, where n = the number of iterations to process.

  • PDIFFAVE - Average PDIFF between the last n iterations, where n = the number of iterations to process.

  • PDIFFCHANGEMIN - Minimum change in PDIFF between the last n iterations, where n = the number of iterations to process.

  • PDIFFCHANGEMAX - Maximum change in PDIFF between the last n iterations, where n = the number of iterations to process.

  • PDIFFCHANGEAVE - Average change in PDIFF between the last n iterations, where n = the number of iterations to process.

  • RMSEMIN - Minimum RMSE between the last n iterations, where n = the number of iterations to process.

  • RMSEMAX - Maximum RMSE between the last n iterations, where n = the number of iterations to process.

  • RMSEAVE - Average RMSE between the last n iterations, where n = the number of iterations to process.

  • RMSECHANGEMIN - Minimum change in RMSE between the last n iterations, where n = the number of iterations to process.

  • RMSECHANGEMAX - Maximum change in RMSE between the last n iterations, where n = the number of iterations to process.

  • RMSECHANGEAVE - Average change in RMSE between the last n iterations, where n = the number of iterations to process.

In many applications, only a few ILOOP statements will be required. For example, an assignment would require only the following statements:

Example of most simple assignment

Assume NETI contains values to obtain T0.

RUN PGM=HIGHWAY
   FILEI NETI=..., MATI=...
   FILEO NETO=...
   PHASE=ILOOP
   PATHLOAD VOL=MI.1.1, PATH=TIME
ENDRUN

Example of _SKIPTOI

/* In this example, the first zone will be processed and then jump to I=100. */
; Therefore, zones 2-99 will be skipped.
RUN PGM=HIGHWAY
   FILEI NETI=..., MATI=...
   FILEO NETO=...
   PHASE=ILOOP
      PATHLOAD VOL=MI.1.1, PATH=TIME
_skiptoi=100
ENDRUN

Getting started with assignment

Using the Highway program is simple if all the input data is in the proper format and the normal procedure is adhered to, but it can be somewhat more difficult if deviations from the normal procedure is desired. In this section we would like to walk the novice users through the steps of setting up the scripts for typical situations.

To perform a typical traffic assignment, all that is needed is an input network and a trip matrix. If the network is in the proper format (contains the required variables) only a few statements are required. While the program bases its computations upon generalized costs, most users tend to think of assignments in terms of time.

To accommodate this, the program assumes that cost is equal to time, unless the user specifies otherwise. In the examples below we will assume that time is the basis for the process.

We wish to do a peak-hour assignment, and the network has the following variables.

  • T0 - Link free flow time

  • DISTANCE - Optional, but useful for certain statistics

  • C - Link capacity in veh/hr

Base case is therefore:

RUN PGM=HIGHWAY   ; simple case
   NETI = mybase.net
   MATI = mytrips.mat   ; peak O-D trips
   NETO = loaded.net
   PHASE = ILOOP
      PATH=TIME, VOL[1]=mi.1.1
ENDRUN

This script will assign the trips from MATI[1] to the paths based upon TIME. It will adjust link times between iterations based upon the congestion levels. By default, up to 10 iterations of assignment and capacity restraint will be run; it will stop sooner if equilibrium convergence is reached before 10 iterations.

In the following examples we will work from this same template and to keep reading to a minimum, we will not include the RUN, NETI, MATI, NETO, and ENDRUN statements. Thus, our illustration script would look like this:

PHASE = ILOOP
   PATH=TIME, VOL[1]=mi.1.1

Examples show:

Daily assignment

Now let’s add a few complications: The trip matrix contains daily trips, and we wish to do a daily assignment. The only thing that we need to do is to get the capacity into the correct units (we’ll assume that daily capacity is 10 times the hourly capacity). We can do this in one of several ways, but let’s just do the simplest, by adding a capacity factor.

PARAMETERS CAPFAC=10; factor NETI capacity by 10 to get daily capacity
PHASE = ILOOP
   PATH=TIME, VOL[1]=mi.1.1

Returning to the base case, let’s now assume that you wish to do an assignment and get the volume on each link that is associated with only the trips that use a certain link. We do this by the typical process, but add an additional select link assignment to the typical assignment. Because this adds another volume set to the process the program will automatically want to sum the two volume sets together to perform capacity restraint. We have to tell the program to not add the selected link volumes. The volume used in each link’s capacity restraint is determined by the program by performing the V function which by default is: V=VOL [1]+… VOL[n], where n is the highest volume set in the setup.

Note: VOL[1], VOL[2], etc must be used with FUNCTION V. V1, V2, etc will generate incorrect results.

So, we replace the function in the following manner:

FUNCTION  V=VOL[1]
PHASE = ILOOP
   PATH=TIME, VOL[1]=mi.1.1,
      MW[1]=mi.1.1, SELECTLINK=(L=2001-2002),
VOL[2]=mw[1]

In this case, work matrix 1 (MW[1]) is computed to be only the trips from MATI whose paths use the selected link. That matrix is then assigned to volume set 2 (VOL[2]). Because we supplied the V function, capacity restraint will only involve VOL[1].

As a side note, when using SELECTLINK and the TURNS control statement in the same HIGHWAY program, care must be taken. Please see TURNS for more information.

Add truck assignment on same paths

Base case plus assigning the trucks from the second matrix on MATI. Trucks use same paths as cars and the combined volumes are used in the capacity restraint.

PHASE = ILOOP
   PATH=TIME, VOL[1]=mi.1.1, VOL[2]=mi.1.2

Add truck assignment on separate paths

Base case plus assign the trucks from the second matrix on MATI. Trucks use a variable from NETI as their base path times, those times will remain constant throughout the assignment.

PHASE = LINKREAD
   LW.TRKTIME = LI.TRUCKTIME
PHASE = ILOOP
   PATH=TIME, VOL[1]=mi.1.1
   PATH=LW.TRKTIME, VOL[2]=mi.1.2

Use preloaded truck volumes

Base case but include the volumes from a prior assignment on the network as additional volumes. Assume that truck trips were assigned, and you wish to use the volumes (plus 30 percent to get passenger car equivalency) in determining total congestion.

PHASE = LINKREAD
   LW.TRKVOL = LI.V_1 ; save the prior assignment volumes
ENDPHASE
FUNCTION V=VOL[1]+LW.TRKVOL*1.3
PHASE = ILOOP
   PATH=TIME, VOL[1]=mi.1.1
ENDPHASE

Separate trips on separate paths

This involves more planning and a bit more script to set up the process. In this scenario, we will assume that one matrix will be assigned to the minimum time paths, but when the paths for the other matrix are developed, the link times are different then the times used for the first matrix. A typical situation occurs when trucks basically operate at a lower speed than cars. In this example, we will establish a time factor to adjust the time on all links. The LINKREAD phase will establish an array (LW.TRKTIME) of times to be used in assignment of the truck trips. After the first iteration, the program would automatically adjust the car times, but there is no automatic way to adjust the truck times. So, we have to introduce an ADJUST phase, in which we do the truck time adjustment for the next iteration.

PHASE = LINKREAD
   T0 = LI.DISTANCE * 60 / LI.SPEED
   TRKFAC = 1.0
   IF (LI.FUNCTYPE == 15, 25,35,45,55,65,75) TRKFAC = 1.2
   LW.TRKTIME = T0 * TRKFAC
ENDPHASE
FUNCTION V = VOL[1] + VOL[2]*1.3
PHASE = ILOOP
   PATH = TIME, VOL[1] = mi.1.1
   PATH = LW.TRKTIME, VOL[2] = mi.1.2
ENDPHASE
PHASE = ADJUST
   LW.TRKTIME = TIME * TRKFAC
ENDPHASE

Assignment of trips to HOV facilities

Base case plus LINKREAD to flag HOV links. We will use 2+ and 3+ facilities, which are flagged in the network variable named HOV. The trip matrices have been previously split into matrices that could not use any HOV links, those that could use 2+ facilities, and those that could use 3+ facilities, stored in mi.1.1, mi.1.2, and mi.1.3, respectively.

PHASE=LINKREADIF(LI.HOV==2)ADDTOGRP=2IF(LI.HOV==3)ADDTOGRP=3PHASE=ILOOPPATH=TIME,EXCLUDEGROUP=2-3,VOL[1]=mi.1.1PATH=TIME,EXCLUDEGROUP=3,VOL[2]=mi.1.2PATH=TIME,VOL[3]=mi.1.3

Path-based tolls

This section describes how to incorporate path-based tolls. This section discusses:

Network development

To use the path-based tolling TOLLMATI function, you must follow several rules when coding closed toll systems. Violating any of these rules causes CUBE Voyager to terminate.

  • Each toll facility must operate as a completely closed system where users can access and egress the facility only by crossing specified toll gates.

    • Every on-gate must have a unique number (1-999).

    • Every off-gate must have a unique number (1-999).

    • Every toll-road link must be identified as such (that is, value is not 0 and corresponds to a unique toll system).

    • Every on-gate/off-gate combination should serve only one unique toll system. This requires that the network toll links connecting an on-gate/off-gate combination, should be coded with the same toll system value in the TOLLROAD attribute.

  • Each network link must have three attributes, which designate the link’s role in the toll system. You specify the attribute names in a FILEI TOLLMATI statement. The attributes store:

    • On-gate number

    • Off-gate number

    • Toll-road indication

  • On-gate and off-gate fields can have a toll system ID applied via the TOLLROAD variable.

    If it is not specified, the system attempts to set the value for the gate link via any connected toll road links. If the toll system ID for the gate cannot be determined, an error is flagged.

    The path building and tracing for tolls is performed separately for each toll system so that only a single toll system is considered at any time, hence toll on and off ramps sharing A or B nodes will not be incorrectly considered in the path build.

  • A toll record must specify the toll for every possible on-off combination of toll gates. You specify toll records in a FILEI TOLLMATI file.

  • Toll access rules:

    • Toll on-ramps:

      • Inbound link must be a non-toll-road link or a toll off- link.

      • Outbound link must be a toll-road link or a toll off-link.

    • Toll off-ramps:

      • Inbound link must be a toll-road link or a toll on-link.

      • Outbound link must be a non-toll- road link or a toll on- link.

    • Toll-road links:

      • Inbound link must be a toll-road link or a toll on-ramp.

      • Outbound link must be a toll-road link or a toll off-link.

Toll type Inbound link must be Outbound link must be Inbound link may not be Outbound link may not be
On-ramp Non-toll-road off-ramp Toll-road off- ramp Toll-road on- ramp Non-toll-road on-ramp
Off-ramp Toll-road on- ramp Non-toll-road on-ramp Non-toll road Toll-road off- ramp
Toll road Toll-road on-ramp Toll-road off-ramp Non-toll-road off-ramp Non-toll-road on-ramp

Path development

To include tolls in path development, specify the keyword TOLLMATI= on a PATHLOAD statement. The first value for TOLLMATI refers to the FILEI TOLLMATI[#]. An optional second value can specify which toll set from the TOLLMATI records to use.

The specification for the TOLLMATI records is as follows:

FILEI TOLLMATI[#]=filename, ENTRYGATE= EXITGATE=
TOLLS= NETIENTRY= NETIEXIT= NETITOLLROAD=

The file may be a DBF, an MDB-element, or a delimited text file. For DBF or MDB files, you must name ENTRYGATE and EXITGATE to indicate which fields on the record contain the on- and off-gate numbers, and TOLLS must name the fields containing the toll values. The first value for TOLLS is toll set 1, the second value is set 2, and so forth. For delimited text files, the values are field numbers instead of names. There may be up to ten TOLLMATI record numbers, and up to ten toll sets. If any of these values is not specified, the default is the relative field on the record (ENTRYGATE is 1, EXITGATE is 2, and TOLL is 3).

Note: If a record exists for a gate-to-gate combination (for the TOLLMATI#), but does not contain a specific toll (value missing or blank), CUBE Voyager assumes a toll value of zero.

The NETI… keywords indicate the NETI link attributes that contain the values for the ramp and road links. You can use these keywords on any FILEI TOLLMATI statement. If you use the keywords on more than one such statement, they must have the same values. If any are unnamed, the defaults names are: TOLLENTRY, TOLLEXIT, TOLLROAD.

The program will fatally terminate if:

  • A link has a nonzero value on more than one of the required toll attributes.

  • More than one link has the same on-ramp value.

  • More than one link has the same off-ramp value.

  • A possible on-to-off route does not have a toll specified. Zero is an acceptable value.

  • There is a violation of the above access rules.

  • If an on-gate/off-gate combination serves more than one toll system.

At the beginning of each iteration, the program determines the on- off combinations that are possible for each PATHLOAD statement. It checks if there is a toll for each of those combinations, and if not, it fatally terminates. It saves those on-off combinations and uses them during the PATHLOAD statement; therefore, do not revise the PATH=array within the iteration. With most toll systems, altering the array would probably not cause a different routing between on-off ramps, but, the on-off travel costs could become incompatible with the array costs. In some systems, changes in the path array might cause a different on-off routing, but since the toll routings and costs are fixed for the iteration, the application does not consider such changes. The PATHLOAD path-building process does not directly use the toll facility links; instead, the process uses the predetermined combinations. During path building, the new PATHTOLL keyword value can be used to skim the toll values for the paths (MW[1]=PATHTOLL). Any I-J path that traversed one or more combinations of entry and exit gates will have the accumulated toll along the path placed in the matrix.

For an example of a script using TOLLMATI, see Example 7: Using TOLLMATI to incorporate closed system Tolls in the Pathbuilding process.

Multiple user class assignment using generalized cost functions

You may skip ahead to:

HIGHWAY supports assigning volumes between multiple user classes, such as High Occupancy (HOV) and Low Occupancy (LOV) vehicles.

For example, to run a two-class assignment process with a different cost function for each user class, the user should use LW variables to define each cost function. These will be used to build paths in the ILOOP phase. This requires two PATHLOAD commands: the first one assigns VOL[1] based on PATH = LW.COST_LOV, and the second one assigns VOL[2] based on PATH = LW.COST_HOV.

In the ADJUST phase the user should calculate the variable COST as the weighted average of the two costs. This allows HIGHWAY to compute the total cost and convergence measures based on the variable COST. If COMBINE=AVE is used, the FUNCTION COST equation can contain LW variables (see below, Example A: COMBINE = AVE). If COMBINE=EQUI is used, the FUNCTION COST equation cannot contain LW variables that are function of volume changes (such as TIME). In this case, LW variables must be replaced with their formula inside the FUNCTION COST equation (see COST, and Example B: COMBINE = EQUI).

In the following examples, observe that:

  • When total volume after an iteration is computed using FUNCTION V, VOL[1] and VOL[2] represent the volume sets, and not V1 and V2.

  • When COMBINE=EQUI is used, the LW.COST_HOV (and LOV) work variables should not be used in FUNCTION COST. If FUNCTION COST contains the work variables, the equilibrium process uses the incorrect TIME values referred in the previous (“not current”) iteration because the work variables are updated following the equilibrium process in the ADJUST phase.

Example A: COMBINE = AVE

; Do not change filenames or add or remove FILEI/FILEO statements using an editor. Use CUBE/Application Editor.

RUN PGM=HIGHWAY PRNFILE="C:\EX_MC_EQUI\MCHWY00J.PRN" MSG='LW.COSTs & FUNC COST'

FILEI MATI[1] = "C:\EX_MC_EQUI\MCMAT00A.MAT"
FILEO NETO = "C:\EX_MC_EQUI\MCHWY00J.NET"
FILEI NETI = "C:\EX_MC_EQUI\data\BASE.NET"

DIST_COST_LOV = 0.3 ; User Class 1
DIST_COST_HOV = 0.5 ; User Class 2

PAR COMBINE=AVE MAXITERS={MAXITERS} GAP=0.0001

PROCESS PHASE=LINKREAD
T0 = (LI.DISTANCE/LI.SPEED)*60
C = LI.CAP
LINKCLASS = LI.FUNC_CLASS
IF (LI.FUNC_CLASS == 1,1.5) LINKCLASS=1 ; Freeways, tollways & HOV
IF (LI.FUNC_CLASS == 2-3) LINKCLASS=2 ; Ramps & expressways
IF (LI.FUNC_CLASS == 4-5) LINKCLASS=3 ; Arterial streets
IF (LI.FUNC_CLASS == 6) LINKCLASS=4 ; Local / collector
IF (LI.FUNC_CLASS == 9-10) LINKCLASS=10 ; Connectors /dummy
IF (LI.NAME='HOV') ADDTOGROUP=1
IF (LI.NAME='RAILACCESS') ADDTOGROUP=9
IF (ITERATION=0)
LW.COST_LOV = T0 + DIST_COST_LOV * LI.DISTANCE
LW.COST_HOV = T0 + DIST_COST_HOV * LI.DISTANCE
ENDIF
ENDPROCESS

PROCESS PHASE=ILOOP
PATHLOAD PATH = LW.COST_LOV VOL[1]=MI.1.1 EXCLUDEGROUP=1,9
PATHLOAD PATH = LW.COST_HOV VOL[2]=MI.1.2 EXCLUDEGROUP=9
ENDPROCESS

PROCESS PHASE=ADJUST
FUNCTION {
V=VOL[1]+VOL[2]
TC[1] = T0 *(1+0.18*(V/C)^8.5) ; Freeways, tollways & HOV
TC[2] = T0 *(1+1.00*(V/C)^5.0) ; Ramps & expressways
TC[3] = T0 *(1+0.70*(V/C)^5.0) ; Arterial streets
TC[4] = T0 *(1+1.40*(V/C)^5.0) ; Local / collector
TC[10]= T0 ; No congestion degradation on centroid connectors
}
LW.COST_LOV = TIME + DIST_COST_LOV * LI.DISTANCE
LW.COST_HOV = TIME + DIST_COST_HOV * LI.DISTANCE

FUNCTION COST = (LW.COST_LOV * V1 + LW.COST_HOV * V2) /
CmpNumRetNum(V,'=',0,1,V) ; cost function

ENDPROCESS

;PROCESS PHASE=CONVERGE
;ENDPROCESS

ENDRUN

Example B: COMBINE = EQUI

; Do not change filenames or add or remove FILEI/FILEO statements using an editor. Use CUBE/Application Editor.
RUN PGM=HIGHWAY PRNFILE="C:\EX_MC_EQUI\MCHWY00J.PRN" MSG='LW.COSTs & FUNC COST'
FILEI MATI[1] = "C:\EX_MC_EQUI\MCMAT00A.MAT"
FILEO NETO = "C:\EX_MC_EQUI\MCHWY00J.NET"
FILEI NETI = "C:\EX_MC_EQUI\data\BASE.NET"

DIST_COST_LOV = 0.3 ; User Class 1
DIST_COST_HOV = 0.5 ; User Class 2

PAR COMBINE=EQUI MAXITERS={MAXITERS} GAP=0.0001

PROCESS PHASE=LINKREAD
T0 = (LI.DISTANCE/LI.SPEED)*60
C = LI.CAP
LINKCLASS = LI.FUNC_CLASS
IF (LI.FUNC_CLASS == 1,1.5) LINKCLASS=1 ; Freeways, tollways & HOV
IF (LI.FUNC_CLASS == 2-3) LINKCLASS=2 ; Ramps & expressways
IF (LI.FUNC_CLASS == 4-5) LINKCLASS=3 ; Arterial streets
IF (LI.FUNC_CLASS == 6) LINKCLASS=4 ; Local / collector
IF (LI.FUNC_CLASS == 9-10) LINKCLASS=10 ; Connectors /dummy
IF (LI.NAME='HOV') ADDTOGROUP=1
IF (LI.NAME='RAILACCESS') ADDTOGROUP=9
IF (ITERATION=0)
LW.COST_LOV = T0 + DIST_COST_LOV * LI.DISTANCE
LW.COST_HOV = T0 + DIST_COST_HOV * LI.DISTANCE
ENDIF
ENDPROCESS

PROCESS PHASE=ILOOP
PATHLOAD PATH = LW.COST_LOV VOL[1]=MI.1.1 EXCLUDEGROUP=1,9
PATHLOAD PATH = LW.COST_HOV VOL[2]=MI.1.2 EXCLUDEGROUP=9
ENDPROCESS

PROCESS PHASE=ADJUST
FUNCTION {
V=VOL[1]+VOL[2]
TC[1] = T0 *(1+0.18*(V/C)^8.5) ; Freeways, tollways & HOV
TC[2] = T0 *(1+1.00*(V/C)^5.0) ; Ramps & expressways
TC[3] = T0 *(1+0.70*(V/C)^5.0) ; Arterial streets
TC[4] = T0 *(1+1.40*(V/C)^5.0) ; Local / collector
TC[10]= T0 ; No congestion degradation on centroid connectors
}
LW.COST_LOV = TIME + DIST_COST_LOV * LI.DISTANCE
LW.COST_HOV = TIME + DIST_COST_HOV * LI.DISTANCE

FUNCTION COST= ((TIME + DIST_COST_LOV * LI.DISTANCE) * V1 + (TIME +
DIST_COST_HOV * LI.DISTANCE) * V2) / CmpNumRetNum(V,'=',0,1,V) ; cost function
ENDPROCESS

;PROCESS PHASE=CONVERGE
;ENDPROCESS

ENDRUN